// 包含必要的系统头文件
#include <sys/socket.h>    // Socket接口
#include <netinet/in.h>    // 网络地址结构
#include <arpa/inet.h>     // IP地址转换函数
#include <unistd.h>        // UNIX标准函数
#include <stdio.h>         // 标准输入输出
#include <string.h>        // 字符串处理
#include <stdlib.h>        // 标准库函数

// 打印使用说明
void Usage() {
    printf("usage: ./server [ip] [port]\n");
}

int main(int argc, char* argv[]) {
    // 检查命令行参数
    if (argc != 3) {  // 需要IP地址和端口两个参数
        Usage();
        return 1;
    }

    // 创建TCP Socket
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");  // 打印错误信息
        return 1;
    }

    // 配置服务器地址结构
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;                    // 使用IPv4
    addr.sin_addr.s_addr = inet_addr(argv[1]);    // 设置IP地址
    addr.sin_port = htons(atoi(argv[2]));         // 设置端口号

    // 绑定Socket到指定地址和端口
    int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
    if (ret < 0) {
        perror("bind");
        return 1;
    }

    // 开始监听连接请求
    ret = listen(fd, 10);  // 最多排队10个连接
    if (ret < 0) {
        perror("listen");
        return 1;
    } 

    // 主循环：处理客户端连接
    for (;;) {
        // 接受新的客户端连接
        struct sockaddr_in client_addr;  // 客户端地址信息
        socklen_t len;
        int client_fd = accept(fd, (struct sockaddr*)&client_addr, &len);
        if (client_fd < 0) {
            perror("accept");
            continue;  // 继续等待下一个连接
        }

        // 读取客户端请求
        char input_buf[1024 * 10] = {0};  // 10KB的缓冲区
        ssize_t read_size = read(client_fd, input_buf, sizeof(input_buf) - 1);
        if (read_size < 0) {
            return 1;  // 读取失败
        }

        // 打印收到的HTTP请求
        printf("[Request] %s", input_buf);

        // 构造HTTP响应
        char buf[1024] = {0};
        const char* hello = "<h1>hello world</h1>";  // 响应体内容
        // 构造HTTP响应头和响应体
        sprintf(buf, "HTTP/1.0 200 OK\nContent-Length:%lu\n\n%s", 
                strlen(hello), hello);

        // 发送响应给客户端
        write(client_fd, buf, strlen(buf));
    }

    return 0;
}